﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Speech;
using System.Speech.Recognition;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;

namespace Speech_Recognition
{
    public partial class Form1 : Form
    {
        private string this_path = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
        SpeechRecognitionEngine recEngine = new SpeechRecognitionEngine();

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            LoadList();

            recEngine.SetInputToDefaultAudioDevice();
            recEngine.SpeechRecognized += recEngine_SpeechRecognized;
            recEngine.RecognizeAsync(RecognizeMode.Multiple); //开始录音
        }

        private class CommandGrammer
        {
            public string key, execpath;
            public int tring = 1;
            public bool isSearch = false;
            public CommandGrammer(string k, int t, string e, bool issear)
            {
                key = k;
                execpath = e;
                isSearch = issear;
                tring = t;
            }
        }

        private List<CommandGrammer> GrammarList = new List<CommandGrammer>();
        private void LoadList()
        {
            GrammarList.Clear();
            if (File.Exists(this_path + "command.config"))
            {
                StreamReader r = new StreamReader(this_path + "command.config", Encoding.UTF8);
                while (!r.EndOfStream)
                {
                    string s1=r.ReadLine(), s2=r.ReadLine(), s3=r.ReadLine(), s4;
                    if (s3 == "true" || s3 == "false")
                    {
                        s4 = s3;
                        s3 = s2;
                        s2 = "shell";
                    }
                    else s4 = r.ReadLine();
                    GrammarList.Add(new CommandGrammer(s1, Tring.ToTring(s2), s3, s4 == "true"));
                    //MessageBox.Show(s1 + s2 + s3 + s4);
                }
                r.Close();
            }
            Choices preCmd = new Choices();

            string[] choices = new string[GrammarList.Count + 3];
            choices[0] = "停止识别";
            choices[1] = "窗口置顶";
            choices[2] = "取消置顶";
            int i = 3;
            foreach (CommandGrammer c in GrammarList)
                choices[i++] = c.key;

            preCmd.Add(choices);
            GrammarBuilder gb = new GrammarBuilder();
            gb.Append(preCmd);
            Grammar gr = new Grammar(gb);
            recEngine.LoadGrammar(gr);  //设置语法
        }

        [DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)]
        public static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);

        private void recEngine_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {
            this.label1.Text = e.Result.Text;

            string res = e.Result.Text;
            if (res == "停止识别")
            {
                recEngine.RecognizeAsyncStop(); //停止识别
                this.button_Stop.Text = "识别";
            }
            else if (res == "窗口置顶")
            {
                this.TopMost = !this.TopMost;
            }
            else if (res == "取消置顶")
                this.TopMost = false;
            /*else if (res.IndexOf("记事") != -1)
                Process.Start("notepad");
            else if (res.IndexOf("画图") != -1)
                Process.Start("mspaint");
            else if (res.IndexOf("浏览器") != -1)
                Process.Start("https://www.baidu.com/");
            else if (res.IndexOf("文件管理") != -1)
                Process.Start("explorer");
            else if (res.IndexOf("翻译") != -1)
                Process.Start("https://fanyi.baidu.com/");*/

            foreach (CommandGrammer c in GrammarList)
            {
                if (c.isSearch)
                {
                    if (res.ToLower().IndexOf(c.key.ToLower()) != -1)
                    {
                        if(c.tring == Tring.Shell)
                        try
                        {
                            Process.Start(c.execpath);
                        }
                        catch (Exception)
                        {
                            MessageBox.Show("无法打开 " + c.execpath + " ，请确保路径正确", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                        else
                        {
                            string[] keybd = c.execpath.Split('+');//通过+分割
                            List<string> popKey = new List<string>();
                            foreach(string s in keybd)
                            {
                                if (s == "Ctrl")
                                {
                                    keybd_event((byte)17, 0, 0, 0);
                                    popKey.Add("Ctrl");
                                }
                                else if(s=="Shift")
                                {
                                    keybd_event((byte)16, 0, 0, 0);
                                    popKey.Add("Shift");
                                }
                                else if (s == "Alt")
                                {
                                    keybd_event((byte)18, 0, 0, 0);
                                    popKey.Add("Alt");
                                }
                                else if (s == "Down")
                                {
                                    keybd_event((byte)Keys.Down, 0, 0, 0);
                                    keybd_event((byte)Keys.Down, 0, 2, 0);
                                    break;
                                }
                                else if (s == "Up")
                                {
                                    keybd_event((byte)Keys.Up, 0, 0, 0);
                                    keybd_event((byte)Keys.Up, 0, 2, 0);
                                    break;
                                }
                                else if (s == "Left")
                                {
                                    keybd_event((byte)Keys.Left, 0, 0, 0);
                                    keybd_event((byte)Keys.Left, 0, 2, 0);
                                    break;
                                }
                                else if (s == "Right")
                                {
                                    keybd_event((byte)Keys.Right, 0, 0, 0);
                                    keybd_event((byte)Keys.Right, 0, 2, 0);
                                    break;
                                }
                                else if(s[0] == 'F' && s.Length > 1)
                                {
                                    int x;
                                    int.TryParse(s.Substring(1), out x);
                                    keybd_event((byte)(111 + x), 0, 0, 0);
                                    keybd_event((byte)(111 + x), 0, 2, 0);
                                    break;
                                }
                                else
                                {
                                    keybd_event((byte)s[0], 0, 0, 0);
                                    keybd_event((byte)s[0], 0, 2, 0);
                                    break;
                                }
                            }
                            foreach(string s in popKey)
                            {
                                if(s=="Ctrl")
                                    keybd_event((byte)17, 0, 2, 0);
                                else if (s == "Shift")
                                    keybd_event((byte)16, 0, 2, 0);
                                else if (s == "Alt")
                                    keybd_event((byte)18, 0, 2, 0);
                            }
                        }

                    }
                }
                else if (res.ToLower() == c.key.ToLower())
                    try
                    {
                        Process.Start(c.execpath);
                    }
                    catch (Exception)
                    {
                        MessageBox.Show("无法打开 " + c.execpath + " ，请确保路径正确", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
            }
        }

        private void button_Stop_Click(object sender, EventArgs e)
        {
            Button b = (Button)sender;
            if(b.Text == "识别")
            {
                recEngine.RecognizeAsync(RecognizeMode.Multiple);
                b.Text = "停止";
            }
            else
            {
                recEngine.RecognizeAsyncStop(); //停止识别
                b.Text = "识别";
            }
        }

        private void lbl_Command_Click(object sender, EventArgs e)
        {
            bool isReRead = false;
            if(this.button_Stop.Text == "停止")
            {
                isReRead = true;
                recEngine.RecognizeAsyncStop(); //停止识别
                this.button_Stop.Text = "识别";
            }
            Form_Command fc = new Form_Command();
            fc.ShowDialog();

            LoadList();
            if(isReRead)
            {
                recEngine.RecognizeAsync(RecognizeMode.Multiple);
                this.button_Stop.Text = "停止";
            }
        }

        private void lbl_Command_MouseEnter(object sender, EventArgs e)
        {
            this.toolTip_Help.Show("如何使用？\n在识别时对着麦克风说出命令即可执行，支持自定义命令和内置命令。\n内置命令：\n1.停止识别：停止识别语音\n2.窗口置顶：将语音窗口置顶\n3.取消置顶：将语言窗口取消置顶", this, this.lbl_Command.Left + this.lbl_Command.Width, this.lbl_Command.Top + this.lbl_Command.Height);
        }

        private void lbl_Command_MouseLeave(object sender, EventArgs e)
        {
            this.toolTip_Help.Hide(this.lbl_Command);
        }
    }
}
